<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>作用域与作用域链</title>
</head>

<body>
    <script>
        /**
         * 作用域与作用域链
         * 1. 理解

            作用域就是一块"地盘"，一个代码段所在的区域
            它是静态的（相对于上下文对象），在编写代码时就产生了（重点是编写代码的时候产生的）
            2. 分类

                全局作用域
                函数作用域
                块作用域（ES6）
            3. 作用

                隔离变量，不同作用域下同名变量不会有冲突！

            4. 作用域和执行上下文区别
                区别1：
                    全局作用域之外，每个函数都会创建自己的作用域，作用域在函数定义时就已经确定了。而不是在函数调用时
                    全局执行上下文环境是在全局作用域确定之后，js代码马上执行之前创建
                    函数执行上下文是在调用函数时，函数体代码执行之前创建
                区别2：
                    作用域是静态的，只要函数定义好了就一直存在，且不会再变化
                    执行上下文是动态的，调用函数时创建，函数调用结束时就会自动释放
            5. 联系

                上下文环境（对象）是从属于所在的作用域
                全局上下文环境 ===> 全局作用域
                函数上下文环境 ===> 对应的函数作用域
            6. 作用域链

                多个上下级关系的作用域形成的链，它的方向是从下向上的（从内到外），查找变量时就是沿着作用域链来查找的
                查找一个变量的查找规则：
                    在当前作用域下的执行上下文中查找对应的属性，如果有就直接返回，否则进入上一级
                    在上一级作用域的执行上下文中查找对应的属性，如果有就直接返回，否则进入更上一级
                    再次执行的相同操作，直到全局作用域，如果还找不到就抛出找不到的异常
        */

        /**
         * 案例1
        */
        // var x = 10;
        // function fn() {
        //     console.log(x);
        // }
        // function show(f) {
        //     var x = 20;
        //     f();
        // }
        // show(fn);  //10  fn的作用域里没有x，就出去找，找到x=10，fn的上级作用域是在代码创建的时候就确定的，为全局作用域window，与在什么时候什么位置调用无关
        /**
        * 案例2
       */
        var fn = function () {
            console.log(fn)
        }

        fn()  //输出整个fn函数

        var obj = {
            fn2: function () {
                console.log(fn2)//此时的fn2为全局作用域window，但是全局window下面没有，所以报错
                // console.log(this.fn2)//此时的fn2为全局作用域this为obj
                // console.log(obj.fn2)//此时的fn2为全局作用域为obj
            }
        }
        obj.fn2() //报错 除非是this.fn2才能调用成功 
    </script>
</body>

</html>